#pragma once

#define _CRT_SECURE_NO_DEPRECATE 

#include <cstdlib>
#include <ctime>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <string>
#include <cmath>
#ifndef WIN32
#include <sys/time.h>
#endif

typedef unsigned int uint;
typedef unsigned char uchar;

using namespace std;

//--------------------------------------//
// Functions                            //
// Wei Ye -- 07/Apr/2012                //
//--------------------------------------//

template <typename T>
inline int argmax(const vector<T> &inVect) {
    T maxValue = inVect[0];
    int maxIndex = 0, i = 1;
    vector<T>::const_iterator itr(inVect.begin() + 1), end(inVect.end());
    while (itr != end) {
        if (*itr > maxValue) {
            maxValue = *itr;
            maxIndex = i;
        }

        ++i;
        ++itr;
    }
    return maxIndex;
}

template <typename T>
inline int argmin(const vector<T> &inVect) {
    T minValue = inVect[0];
    int minIndex = 0, i = 1;
    vector<T>::const_iterator itr(inVect.begin() + 1), end(inVect.end());
    while (itr != end) {
        if (*itr < minValue) {
            minValue = *itr;
            minIndex = i;
        }

        ++i;
        ++itr;
    }

    return minIndex;
}

template <typename T>
inline T sum(const vector<T> &inVect) {
    T val = 0;
    vector<T>::const_iterator itr(inVect.begin()), end(inVect.end());
    while (itr != end) {
        val += *itr;
        ++itr;
    }

    return val;
}

// Returns a random number in [0, 1]
inline double randDouble() 
{
    static bool didSeeding = false;

    if (!didSeeding) {
#ifdef WIN32
        srand((unsigned)time(0));
#else
        unsigned int seedNum;
        struct timeval TV;
        unsigned int curTime;

        gettimeofday(&TV, NULL);
        curTime = (unsigned int) TV.tv_usec;
        seedNum = (unsigned int) time(NULL) + curTime + getpid() + getDevRandom();

        srand(seedNum);
#endif
        didSeeding = true;
    }
    return rand() / (RAND_MAX + 1.0);
}

// Returns a random number in [min, max]
inline double randomFromRange(const double &minRange, const double &maxRange) 
{
    return minRange + (maxRange - minRange) * randDouble();
}

inline int randIntFromRange(const int from, const int range) {
    return from + int(range*randDouble());
}

// Poisson sampling
inline int poisson(double A) {
    int k = 0;
    int maxK = 10;
    while (1) {
        double U_k = randDouble();
        A *= U_k;
        if (k > maxK || A < exp(-1.0)) {
            break;
        }
        k++;
    }
    return k;
}

// number to string(in certain format)
inline string int2str( int i, int ndigits )
{
	ostringstream temp;
	temp << setfill('0') << setw(ndigits) << i;
	return temp.str();
}

template <typename T>
inline void printArray(T* arr, int len)
{
	for(int i = 0; i < len; i++)
		cout<<arr[i]<<endl;
}